﻿using System;
using System.Collections;
using System.Collections.Generic;
using System.Linq;
using System.Windows.Forms;

namespace ThreadSafeControls {
    partial class ThreadSafeControl {
        public class ControlCollection : IList<ThreadSafeControl>, IList {

            private readonly ThreadSafeControl _control;

            internal ControlCollection(ThreadSafeControl control) {
                if (control == null)
                    throw new ArgumentNullException("control");

                _control = control;
            }

            public ThreadSafeControl this[int index] {
                get { return _control.ReturnAsync(() => _control.UnderlyingControl.Controls[index].AsThreadSafeControl()); }
                set { throw new InvalidOperationException(); }
            }

            public int Count {
                get { return _control.ReturnAsync(() => _control.UnderlyingControl.Controls.Count); }
            }

            public void Add(Control control) {
                _control.UpdateAsync(() => _control.UnderlyingControl.Controls.Add(control));
            }

            public void Add(ThreadSafeControl control) {
                Add(control.UnderlyingControl);
            }

            public void AddRange(IEnumerable<Control> controls) {
                _control.UpdateAsync(() => _control.UnderlyingControl.Controls.AddRange(controls.ToArray()));
            }

            public void AddRange(IEnumerable<ThreadSafeControl> controls) {
                AddRange(controls.Select(c => c.UnderlyingControl).ToArray());
            }

            public void Clear() {
                _control.UpdateAsync(() => _control.UnderlyingControl.Controls.Clear());
            }

            public bool Contains(Control control) {
                return _control.ReturnAsync(() => _control.UnderlyingControl.Controls.Contains(control));
            }

            public bool Contains(ThreadSafeControl control) {
                return Contains(control.UnderlyingControl);
            }

            public void CopyTo(ThreadSafeControl[] dest, int index) {
                var array = Enumerate().ToArray();
                array.CopyTo(dest, index);
            }

            public ThreadSafeControl[] Find(string key, bool searchAllChildren) {
                return _control.ReturnAsync(() => _control.UnderlyingControl.Controls.Find(key, searchAllChildren))
                    .Select(c => c.AsThreadSafeControl())
                    .ToArray();
            }

            public int IndexOf(Control control) {
                return _control.ReturnAsync(() => _control.UnderlyingControl.Controls.IndexOf(control));
            }

            public int IndexOf(ThreadSafeControl control) {
                return IndexOf(control.UnderlyingControl);
            }

            public int IndexOfKey(string key) {
                return _control.ReturnAsync(() => _control.UnderlyingControl.Controls.IndexOfKey(key));
            }

            public void Remove(Control value) {
                _control.UpdateAsync(() => _control.UnderlyingControl.Controls.Remove(value));
            }

            public bool Remove(ThreadSafeControl value) {
                Remove(value.UnderlyingControl);
                return true;
            }

            public void RemoveAt(int index) {
                _control.UpdateAsync(() => _control.UnderlyingControl.Controls.RemoveAt(index));
            }

            public void RemoveByKey(string key) {
                _control.UpdateAsync(() => _control.UnderlyingControl.Controls.RemoveByKey(key));
            }

            public void SetChildIndex(Control child, int newIndex) {
                _control.UpdateAsync(() => _control.UnderlyingControl.Controls.SetChildIndex(child, newIndex));
            }

            public void SetChildIndex(ThreadSafeControl child, int newIndex) {
                SetChildIndex(child.UnderlyingControl, newIndex);
            }

            public IEnumerator<ThreadSafeControl> GetEnumerator() {
                return Enumerate().GetEnumerator();
            }

            private IEnumerable<ThreadSafeControl> Enumerate() {
                return _control.ReturnAsync(() => _control.UnderlyingControl.Controls)
                    .Cast<Control>()
                    .Select(c => (ThreadSafeControl)c.AsThreadSafeControl());
            }

            #region Explicit Interface Members

            object IList.this[int index] {
                get { return _control.ReturnAsync(() => ((IList)_control.UnderlyingControl.Controls)[index]); }
                set { _control.UpdateAsync(() => ((IList)_control.UnderlyingControl.Controls)[index] = value); }
            }

            bool IList.IsFixedSize {
                get { return ((IList)_control.UnderlyingControl.Controls).IsFixedSize; }
            }

            bool ICollection<ThreadSafeControl>.IsReadOnly {
                get { return false; }
            }

            bool IList.IsReadOnly {
                get { return ((IList)_control.UnderlyingControl.Controls).IsReadOnly; }
            }

            bool ICollection.IsSynchronized {
                get { return ((ICollection)_control.UnderlyingControl.Controls).IsSynchronized; }
            }

            object ICollection.SyncRoot {
                get { return ((ICollection)_control.UnderlyingControl.Controls).SyncRoot; }
            }

            int IList.Add(object value) {
                return _control.ReturnAsync(() => ((IList)_control.UnderlyingControl.Controls).Add(value));
            }

            bool IList.Contains(object value) {
                return _control.ReturnAsync(() => ((IList)_control.UnderlyingControl.Controls).Contains(value));
            }

            void ICollection.CopyTo(Array dest, int index) {
                var array = Enumerate().ToArray();
                array.CopyTo(dest, index);
            }

            int IList.IndexOf(object value) {
                return _control.ReturnAsync(() => ((IList)_control.UnderlyingControl.Controls).IndexOf(value));
            }

            void IList.Insert(int index, object value) {
                _control.UpdateAsync(() => ((IList)_control.UnderlyingControl.Controls).Insert(index, value));
            }

            void IList<ThreadSafeControl>.Insert(int index, ThreadSafeControl value) {
                ((IList)this).Insert(index, value);
            }

            void IList.Remove(object value) {
                _control.UpdateAsync(() => ((IList)_control.UnderlyingControl.Controls).Remove(value));
            }

            IEnumerator IEnumerable.GetEnumerator() {
                return GetEnumerator();
            }

            #endregion

        }
    }
}
